package pool

import (
	"fmt"
	"sync"
	"time"

	"github.com/streadway/amqp"
)

type MQClient struct {
	url    string
	conn   *amqp.Connection
	mutex  sync.Mutex
	closed chan *amqp.Error
}

var clientInstance *MQClient
var once sync.Once

// InitMQClient initializes the singleton MQClient with auto reconnect
func InitMQClient(url string) *MQClient {
	once.Do(func() {
		clientInstance = &MQClient{
			url:    url,
			closed: make(chan *amqp.Error, 1),
		}
		if err := clientInstance.connect(); err != nil {
			//fmt.Errorf("[RabbitMQ] initial connection failed: %v", err)
		}
		go clientInstance.monitorAndReconnect()
	})
	return clientInstance
}

// connect establishes a new RabbitMQ connection
func (c *MQClient) connect() error {
	c.mutex.Lock()
	defer c.mutex.Unlock()

	conn, err := amqp.Dial(c.url)
	if err != nil {
		return err
	}
	c.conn = conn
	c.closed = make(chan *amqp.Error, 1)
	c.conn.NotifyClose(c.closed)
	fmt.Printf("[RabbitMQ] connected successfully")
	return nil
}

// monitorAndReconnect listens for connection close and retries connection
func (c *MQClient) monitorAndReconnect() {
	for {
		err := <-c.closed
		fmt.Printf("[RabbitMQ] connection closed: %v, retrying...\r\n", err)
		for {
			if err := c.connect(); err == nil {
				fmt.Println("[RabbitMQ] reconnected successfully")
				break
			}
			fmt.Printf("[RabbitMQ] reconnect failed, retrying in 5s...")
			time.Sleep(5 * time.Second)
		}
	}
}

// GetChannel returns a new channel on the current connection
func (c *MQClient) GetChannel() (*amqp.Channel, error) {
	c.mutex.Lock()
	defer c.mutex.Unlock()
	if c.conn == nil || c.conn.IsClosed() {
		return nil, amqp.ErrClosed
	}
	return c.conn.Channel()
}

// Close gracefully closes the connection
func (c *MQClient) Close() {
	c.mutex.Lock()
	defer c.mutex.Unlock()
	if c.conn != nil && !c.conn.IsClosed() {
		_ = c.conn.Close()
		fmt.Printf("[RabbitMQ] connection closed\r\n")
	}
}
